﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel.Composition;
using System.IO;
using PefStudio.Windows;

namespace PefStudio.SegyViewer
{
    [Export(Contract, typeof(SegyViewerDocument))]
    [Document(Name = "Segy Viewer")]
    public partial class SegyViewerDocument : AbstractFloatDocument, IHasPropertyContainer
    {
        public const string Contract = "PefStudio.SegyViewer";

        public SegyViewerDocument()
        {
            InitializeComponent();

            _traceSets.TraceHeaderExtractStyleChanged += new EventHandler(traceSets_TraceHeaderExtractStyleChanged);
            _traceSets.ReelHeaderExtractStyleChanged += new EventHandler(traceSets_ReelHeaderExtractStyleChanged);
            _traceSets.TracesPerPageChanged += new EventHandler(traceSets_TracesPerPageChanged);
            _traceSets.SamplePointsPerPageChanged += new EventHandler(traceSets_SamplePointsPerPageChanged);
        }

        private const string BaseTitle = "Segy Viewer";

        int _i采样点数 = 0;
        int _i道数 = 0;
        readonly TraceSets _traceSets = new TraceSets();

        string _currentSegyFile = string.Empty;
        public string CurrentSegyFile
        {
            get
            {
                return _currentSegyFile;
            }
            set
            {
                if (value == _currentSegyFile)
                    return;

                _currentSegyFile = value;

                var fileInfo = new FileInfo(_currentSegyFile);
                ReadHeaderInfo(fileInfo);

                tracePicture.采样点数 = _i采样点数;
                tracePicture.道数 = _i道数;

                tracePicture.FileInfo = fileInfo;

                Title = Path.GetFileName(_currentSegyFile) + " - " + BaseTitle;
                ToolTipText = value;
            }
        }

        readonly PropertyContainer _propertyContainer = new PropertyContainer();
        public PropertyContainer PropertyContainer
        {
            get
            {
                _propertyContainer.SelectedObject = _traceSets;
                return _propertyContainer;
            }
        }

        void traceSets_SamplePointsPerPageChanged(object sender, EventArgs e)
        {
            tracePicture.SamplePointsPerPage = _traceSets.SamplePointsPerPage;
        }

        void traceSets_TracesPerPageChanged(object sender, EventArgs e)
        {
            tracePicture.TracesPerPage = _traceSets.TracesPerPage;
        }

        void ReadHeaderInfo(FileInfo fileInfo)
        {
            if (fileInfo == null)
                return;

            var br = new BinaryReader(fileInfo.OpenRead());

            ReadReelTextInfo(br);
            ReadReelHeaderInfo(br);
            ReadTraceHeaderInfo(br);

            br.Close();
        }

        void ReadReelTextInfo(FileInfo fileInfo)
        {
            if (fileInfo == null)
                return;

            var br = new BinaryReader(fileInfo.OpenRead());

            ReadReelTextInfo(br);

            br.Close();
        }

        void ReadReelTextInfo(BinaryReader br)
        {
            br.BaseStream.Position = 0;

            byte[] bytesReelText = br.ReadBytes(3200);

            bytesReelText = Utils.EBCDICToASCII(bytesReelText);
            string text = string.Empty;
            for (int k = 0; k < 40; k++)
            {
                for (int i = 0; i < 80; i++)
                {
                    text += Convert.ToChar(bytesReelText[k * 80 + i]);
                }
                if (k != 39)
                    text += "\r\n";
            }

            txtReelText.Text = text;
        }

        void ReadTraceHeaderInfo(FileInfo fileInfo)
        {
            if (fileInfo == null)
                return;

            var br = new BinaryReader(fileInfo.OpenRead());

            ReadTraceHeaderInfo(br);

            br.Close();
        }

        void ReadTraceHeaderInfo(BinaryReader br)
        {
            br.BaseStream.Position = 3600;

            _i采样点数 = 0;
            _i道数 = 0;
            lsvTraceInfo.Items.Clear();

            List<Field> fields_header = new List<Field>();
            foreach (HeaderField field in _traceSets.TraceHeaderFields)
            {
                fields_header.Add(new Field(field));
            }

            while (br.BaseStream.Position + 240 < br.BaseStream.Length)
            {
                byte[] bytes_trace_header = br.ReadBytes(240);

                int pos = 0;
                foreach (Field field in fields_header)
                {
                    if (field.Size == 4)
                    {
                        field.Value = Utils.ReadBigEndianInt32(bytes_trace_header, pos);
                        pos += 4;
                    }
                    else if (field.Size == 2)
                    {
                        field.Value = Utils.ReadBigEndianInt16(bytes_trace_header, pos);
                        pos += 2;
                    }

                    if (_i道数 == 0 && field.IsSamplePoint == true)
                    {
                        _i采样点数 = field.MinValue;
                    }

                    if (pos >= 240)
                        break;
                }

                br.BaseStream.Position += 4 * _i采样点数;

                _i道数++;
            }

            lsvTraceInfo.BeginUpdate();
            int fieldpos = 1;
            foreach (Field field in fields_header)
            {
                ListViewItem item = new ListViewItem(fieldpos.ToString("000"));
                item.SubItems.Add(field.Name);
                item.SubItems.Add(field.Size.ToString());
                item.SubItems.Add(field.MinValue.ToString());
                item.SubItems.Add(field.MaxValue.ToString());
                item.SubItems.Add(field.Description);

                lsvTraceInfo.Items.Add(item);

                fieldpos += field.Size;
            }
            lsvTraceInfo.EndUpdate();
        }

        void traceSets_TraceHeaderExtractStyleChanged(object sender, EventArgs e)
        {
            FileInfo fileInfo = new FileInfo(_currentSegyFile);
            ReadTraceHeaderInfo(fileInfo);
        }

        void ReadReelHeaderInfo(FileInfo fileInfo)
        {
            if (fileInfo == null)
                return;

            BinaryReader br = new BinaryReader(fileInfo.OpenRead());

            ReadReelHeaderInfo(br);

            br.Close();
        }

        void ReadReelHeaderInfo(BinaryReader br)
        {
            br.BaseStream.Position = 3200;

            lsvReelInfo.Items.Clear();

            byte[] bytes_reel_header = br.ReadBytes(400);

            List<Field> fields_header = new List<Field>();
            foreach (HeaderField field in _traceSets.ReelHeaderFields)
            {
                fields_header.Add(new Field(field));
            }

            int pos = 0;
            foreach (Field field in fields_header)
            {
                if (field.Size == 4)
                {
                    field.Value = Utils.ReadBigEndianInt32(bytes_reel_header, pos);
                    pos += 4;
                }
                else if (field.Size == 2)
                {
                    field.Value = Utils.ReadBigEndianInt16(bytes_reel_header, pos);
                    pos += 2;
                }

                if (pos >= 400)
                    break;
            }

            lsvReelInfo.BeginUpdate();
            int fieldpos = 3201;
            foreach (Field field in fields_header)
            {
                ListViewItem item = new ListViewItem(fieldpos.ToString("000"));
                item.SubItems.Add(field.Name);
                item.SubItems.Add(field.Size.ToString());
                item.SubItems.Add(field.MinValue.ToString());
                item.SubItems.Add(field.Description);

                lsvReelInfo.Items.Add(item);

                fieldpos += field.Size;
            }
            lsvReelInfo.EndUpdate();
        }

        void traceSets_ReelHeaderExtractStyleChanged(object sender, EventArgs e)
        {
            FileInfo fileInfo = new FileInfo(_currentSegyFile);
            ReadReelHeaderInfo(fileInfo);
        }

        class Field
        {
            private HeaderField HeaderField;
            public int MinValue;
            public int MaxValue;

            public Field(HeaderField field)
            {
                HeaderField = field;
            }

            public string Name
            {
                get
                {
                    return HeaderField.Name;
                }
            }

            public string Description
            {
                get
                {
                    return HeaderField.Description;
                }
            }

            public bool IsSamplePoint
            {
                get
                {
                    return HeaderField.IsSamplePoint;
                }
            }

            public int Size
            {
                get
                {
                    return HeaderField.Size;
                }
            }

            public int Value
            {
                set
                {
                    if (value < 0)
                        return;

                    if (MinValue == 0)
                    {
                        MinValue = value;
                    }
                    else if (MinValue > value)
                    {
                        MinValue = value;
                    }
                    else if (MaxValue < value)
                    {
                        MaxValue = value;
                    }
                }
            }
        }
    }
}
